﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using DG.Tweening;
using System;

public class RotateBase : MonoBehaviour
{
    private static GameObject AttactkAudio = GameObject.Find("AudioPlayer/AttackAudio");
    /// <summary>
    /// 六个轴向
    /// </summary>
    private static readonly List<Vector3> Axises = new List<Vector3> { Vector3.right, Vector3.left, Vector3.up, Vector3.down, Vector3.forward, Vector3.back };
    /// <summary>
    /// 用作旋转中心的空物体
    /// </summary>
    public static GameObject RotateCenter = GameObject.Find("RotateCenter");
    /// <summary>
    /// 根据起始和终点的面坐标返回移动数据
    /// </summary>
    /// <param name="from">起始面坐标</param>
    /// <param name="to">终点面坐标</param>
    /// <returns></returns>
    public static MoveData MoveToJudge(DiceData from, DiceData to)
    {
        MoveData moveData = new MoveData();
        //Vector3 targetPosition = to.DiceCoordinate - from.DiceCoordinate;
        if (from.DiceCoordinate == to.DiceCoordinate)// 类型0
        {
            //同一个方块的转动
            moveData.Type = 0;
            //获取方向
            GetDirection(from.GroundTowards, to.GroundTowards, moveData);
            //设置旋转中心为to
            moveData.TurnCenter = from.DiceCoordinate;
        }
        else if (from.GroundTowards == to.GroundTowards)// 类型1
        {
            // 对同方向面的移动
            moveData.Type = 1;
            moveData.Move = to.DiceCoordinate - from.DiceCoordinate;
        }
        else if (from.GroundTowards != to.GroundTowards && from.DiceCoordinate != to.DiceCoordinate)// 类型2
        {
            // 夹角面
            moveData.Type = 2;
            GetDirection(from.GroundTowards, to.GroundTowards, moveData);
            moveData.TurnCenter = from.DiceCoordinate + from.GroundTowards;
        }
        moveData.From = from;
        moveData.To = to;
        return moveData;
    }

    //public static IEnumerator SeparateParent()
    //{

    //    yield return new WaitForSeconds(0.5f);
    //    GameObject.Find("MoveObj").transform.parent = null;
    //}


    //public void TurnHalfPIOnce(Vector3 axis, int toward, GameObject target)
    //{
    //    StartCoroutine(Turning(axis, toward, target));
    //}

    /// <summary>
    /// 平移
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="targetPosition"></param>
    /// <param name="time"></param>
    public static IEnumerator MoveToward(GameObject obj, MoveData moveData, float time, Action nextFunc = null)
    {
        RegistAction(1);
        GameObject target = obj;
        if (obj.tag == "Player")
        {
            target = obj.transform.parent.gameObject;
        }
        int lastLong = (int)(time / Time.fixedDeltaTime);
        Vector3 start = target.transform.position;
        Vector3 end = start + moveData.Move;
        for (int i = 1; i <= lastLong; i++)
        {
            target.transform.position = Vector3.Lerp(start, end, (float)i / lastLong);
            yield return new WaitForFixedUpdate();
        }
        moveData.From.Controller.FlushChild();
        target.transform.parent = moveData.To.Controller.transform.GetChild(0);
        moveData.To.Controller.FlushChild(obj);
        if (nextFunc != null)
        {
            nextFunc();
        }   // 下一个方法：移动（旋转）
        RegistAction(-1);
    }
    /// <summary>
    /// 转向指定角度
    /// </summary>
    /// <param name="target"></param>
    /// <param name="to"></param>
    /// <param name="registe"></param>
    /// <param name="nextFunc"></param>
    /// <returns></returns>
    public static IEnumerator FaceTo(GameObject target, Vector3 to, Action nextFunc = null)
    {       
        Vector3 axis = target.transform.up;
        Vector3 from = ReturnAxis(target.transform.forward);
        Debug.Log(to);
        to = ReturnAxis(to);
        Debug.Log(from + "" + to);
        if (from != to)
        {
            RegistAction(1);

            Quaternion start = target.transform.rotation;
            Quaternion end;
            if ((from + to).magnitude < 0.001)
            {
                List<Vector3> axises = new List<Vector3>(Axises.ToArray());
                for (int i = 0; i < 5; i++)
                {
                    if (!AxisJudgement(axis, axises[i]))
                    {
                        axises.RemoveAt(i + 1);
                        axises.RemoveAt(i);
                        break;
                    }
                }
                axises.Remove(from);
                axises.Remove(to);
                end = Quaternion.FromToRotation(from, axises[0]);
                end = end * start;
                for (int i = 1; i <= 10; i++) // TODO 旋转时间常数放在配置文件中
                {
                    target.transform.rotation = Quaternion.Slerp(start, end, (float)i / 10);
                    yield return new WaitForFixedUpdate();
                }
                start = target.transform.rotation;
                end = Quaternion.FromToRotation(axises[0], to);
                end = end * start;
                for (int i = 1; i <= 10; i++) // TODO 旋转时间常数放在配置文件中
                {
                    target.transform.rotation = Quaternion.Slerp(start, end, (float)i / 10);
                    yield return new WaitForFixedUpdate();
                }

            } // 180旋转
            else
            {
                end = Quaternion.FromToRotation(from, to);
                end = end * start;
                for (int i = 1; i <= 10; i++) // TODO 旋转时间常数放在配置文件中
                {
                    target.transform.rotation = Quaternion.Slerp(start, end, (float)i / 10);
                    yield return new WaitForFixedUpdate();
                }
            } // 90旋转

            RegistAction(-1);
        }
        if (nextFunc != null)
        {
            nextFunc();
        }       
    }

    /// <summary>
    /// 转向到某个角度,可以指定下一个方法
    /// </summary>
    /// <param name="from">朝向的方向,直接使用transform.forward就可以了</param>
    /// <param name="moveData">移动数据</param>
    /// /// <param name="nextFunc">转向之后的本地方法，无则填null</param>
    /// <returns></returns>
    public static IEnumerator FaceTo(Vector3 from, MoveData moveData, Action nextFunc = null)
    {
        RegistAction(1);
        int toward = 0; // 旋转量       
        Vector3 to;
        switch (moveData.Type)
        {
            case 0:
            case 2:
                to = moveData.To.GroundTowards;
                break;
            case 1:
                to = (moveData.To.DiceCoordinate - moveData.From.DiceCoordinate).normalized;
                break;
            default:
                Debug.LogError("移动数据类型错误！");
                to = Vector3.zero;
                break;
        }
        if (moveData.Type == 2) to *= -1;
        if (from != to)
        {
            if (from + to == Vector3.zero)
            {
                toward = 2;
            }
            else
            {
                // TODO 直接调用方法有点问题，先复制过来改改，日后重构需要更改方法的写法
                Vector3 temp = to - from;
                Vector2 from2 = Vector2.zero, to2 = Vector2.zero;
                if (Mathf.Abs(temp.x) < 0.01 && Mathf.Abs(temp.y) > 0.01 && Mathf.Abs(temp.z) > 0.01)// 轴为x
                {
                    from2 = new Vector2(from.y, from.z);
                    to2 = new Vector2(to.y, to.z);
                }
                else if (Mathf.Abs(temp.x) > 0.01 && Mathf.Abs(temp.y) < 0.01 && Mathf.Abs(temp.z) > 0.01)// 轴为y
                {
                    from2 = new Vector2(from.z, from.x);
                    to2 = new Vector2(to.z, to.x);
                }
                else if (Mathf.Abs(temp.x) > 0.01 && Mathf.Abs(temp.y) > 0.01 && Mathf.Abs(temp.z) < 0.01)// 轴为z
                {
                    from2 = new Vector2(from.x, from.y);
                    to2 = new Vector2(to.x, to.y);
                }
                toward = TurnTowardsJudge(from2, to2); // 认为朝向是正向轴
                if (moveData.From.GroundTowards.x < -0.001 || moveData.From.GroundTowards.y < -0.001 || moveData.From.GroundTowards.z < -0.001) // 如果朝向逆轴
                {
                    toward *= -1;
                }
            }
            Quaternion start = moveData.Target.transform.rotation;
            Quaternion end = Quaternion.AngleAxis(toward * 90, moveData.From.GroundTowards) * start;
            for (int i = 1; i <= Mathf.Abs(toward) * 10; i++) // TODO 旋转时间常数放在配置文件中
            {
                moveData.Target.transform.rotation = Quaternion.Slerp(start, end, (float)i / (Mathf.Abs(toward) * 10));
                yield return new WaitForFixedUpdate();
            }
        }

        if (nextFunc != null)
        {
            nextFunc();
        }   // 下一个方法：移动（旋转）

        RegistAction(-1);
    }

    /// <summary>
    /// 绕轴顺时针旋转90°*angle
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="lastLong">动画播放帧数</param>
    /// <returns></returns>
    public static IEnumerator Turning(MoveData moveData, GameObject obj, float time, Action nextFunc = null)
    {
        RegistAction(1);
        GameObject target = obj;
        if (obj.tag == "Player")
        {
            target = obj.transform.parent.gameObject;
        }
        RotateCenter.transform.position = moveData.TurnCenter; // 改变旋转中心位置
        target.transform.parent = RotateCenter.transform; // 挂载旋转中心
        moveData.From.Controller.FlushChild(); // 给地面注销物体
        int lastLong = (int)(time / Time.fixedDeltaTime);
        float turnAngle = moveData.Toward * 90;
        Quaternion start = RotateCenter.transform.rotation;
        Quaternion turn = Quaternion.AngleAxis(turnAngle, moveData.Axis);
        Quaternion end = turn * start;
        for (int i = 1; i <= lastLong; i++)
        {
            RotateCenter.transform.rotation = Quaternion.Slerp(start, end, (float)i / lastLong);
            yield return new WaitForFixedUpdate();
        }
        target.transform.parent = moveData.To.Controller.gameObject.transform;
        RotateCenter.transform.rotation = Quaternion.identity; // 还原旋转中心角度（应该没啥用）
        moveData.To.Controller.FlushChild(obj); // 给地面登记物体
        Debug.Log(target.name + "旋转完成"); // 发送旋转完毕信号
        if (nextFunc != null)
        {
            nextFunc();
        }   // 下一个方法：移动（旋转）
        RegistAction(-1);
    }

    /// <summary>
    /// 给MoveData添加旋转信息 TODO　方法太蠢了，重构时应考虑重写
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <param name="moveData"></param>
    public static void GetDirection(Vector3 from, Vector3 to, MoveData moveData)
    {
        Vector3 temp = to - from;
        if (Mathf.Abs(temp.x) < 0.01 && Mathf.Abs(temp.y) > 0.01 && Mathf.Abs(temp.z) > 0.01)// 轴为x
        {
            moveData.Axis = new Vector3(1, 0, 0);
            moveData.Toward = TurnTowardsJudge(new Vector2(from.y, from.z),
                new Vector2(to.y, to.z));
            //Debug.Log(moveData.Axis + "x轴");
        }
        else if (Mathf.Abs(temp.x) > 0.01 && Mathf.Abs(temp.y) < 0.01 && Mathf.Abs(temp.z) > 0.01)// 轴为y
        {
            moveData.Axis = new Vector3(0, 1, 0);
            moveData.Toward = TurnTowardsJudge(new Vector2(from.z, from.x),
                new Vector2(to.z, to.x));
            //Debug.Log(moveData.Axis + "y轴");
        }
        else if (Mathf.Abs(temp.x) > 0.01 && Mathf.Abs(temp.y) > 0.01 && Mathf.Abs(temp.z) < 0.01)// 轴为z
        {
            moveData.Axis = new Vector3(0, 0, 1);
            moveData.Toward = TurnTowardsJudge(new Vector2(from.x, from.y),
                new Vector2(to.x, to.y));
            //Debug.Log(moveData.Axis + "z轴");
        }
    }

    /// <summary>
    /// 判断旋转方向，从旋转轴正向（视线逆轴方向）看的平面上，顺时针90°为1逆时针90°为-1 
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public static int TurnTowardsJudge(Vector2 from, Vector2 to)
    {
        Vector2 v10 = new Vector2(1, 0),
            v01 = new Vector2(0, 1),
            v20 = new Vector2(-1, 0),
            v02 = new Vector2(0, -1);
        int toward;
        if ((from == v10 && to == v01) ||
            (from == v01 && to == v20) ||
            (from == v20 && to == v02) ||
            (from == v02 && to == v10))// 顺时针
        {
            toward = 1;
        }
        else//逆时针
        {
            toward = -1;
        }
        return toward;
    }

    /// <summary>
    /// 根据两个坐标判断是否可以行动
    /// </summary>
    /// <param name="main">行动发出者</param>
    /// <param name="target">行动目标</param>
    /// <returns></returns>
    public static bool Adjoin(DiceData main, DiceData target)
    {
        //Debug.Log(main.DiceCoordinate + "main");
        if (main.DiceCoordinate == target.DiceCoordinate) // 同一块方块
        {
            if ((main.GroundTowards + target.GroundTowards).magnitude > 0.001) return true;
        }
        else // 不是同一块
        {
            if (main.GroundTowards == target.GroundTowards) // 朝向一致
            {
                Vector3 temp = main.DiceCoordinate - target.DiceCoordinate;
                if (temp.magnitude - 1 < 0.001) return true;
            }
            else // 朝向不一致
            {
                Vector3 temp = main.DiceCoordinate + main.GroundTowards;
                Vector3 temp2 = target.DiceCoordinate + target.GroundTowards;
                if ((temp - temp2).magnitude < 0.001) return true;
            }
        }
        return false;
    }

    /// <summary>
    /// 判断方向，返回值为某轴向
    /// </summary>
    /// <param name="from">转向目标坐标</param>
    /// <param name="to">转向中心坐标</param>
    /// <returns></returns>
    public static Vector3 DirectionJudge(DiceData target, DiceData center)
    {
        Vector3 temp = target.DiceCoordinate + (float)0.5 * target.GroundTowards - center.DiceCoordinate - (float)0.5 * center.GroundTowards;
        Vector3 axis = center.GroundTowards;
        List<Vector3> axises = new List<Vector3>(Axises.ToArray());
        for (int i = 0; i < 5; i++)
        {
            if (!AxisJudgement(axis, axises[i]))
            {
                axises.RemoveAt(i + 1);
                axises.RemoveAt(i);
                break;
            }
        }
        float minDis = 99999;
        Vector3 returnValue = Vector3.zero;
        //Debug.LogError(axises.Count +""+ axises[0] +"" + axises[1] + "" + axises[2] + "" + axises[3]);
        for (int i = 0; i < axises.Count; i++)
        {
            if ((temp - axises[i]).magnitude < minDis)
            {
                minDis = (temp - axises[i]).magnitude;
                returnValue = axises[i];
            }
        }
        //Debug.LogError(returnValue);
        return returnValue;
    }
    /// <summary>
    /// 判断方向，返回值为某轴向
    /// </summary>
    /// <param name="from">转向目标坐标</param>
    /// <param name="to">转向中心坐标</param>
    /// <returns></returns>
    public static Vector3 DirectionJudgeReverse(DiceData target, DiceData center)
    {
        Vector3 temp = target.DiceCoordinate + (float)0.5 * target.GroundTowards - center.DiceCoordinate - (float)0.5 * center.GroundTowards;
        Vector3 axis = center.GroundTowards;
        List<Vector3> axises = new List<Vector3>(Axises.ToArray());
        for (int i = 0; i < 5; i++)
        {
            if (!AxisJudgement(axis, axises[i]))
            {
                axises.RemoveAt(i + 1);
                axises.RemoveAt(i);
                break;
            }
        }
        float minDis = 99999;
        Vector3 returnValue = Vector3.zero;
        //Debug.LogError(axises.Count +""+ axises[0] +"" + axises[1] + "" + axises[2] + "" + axises[3]);
        for (int i = axises.Count - 1; i >= 0; i--)
        {
            if ((temp - axises[i]).magnitude < minDis)
            {
                minDis = (temp - axises[i]).magnitude;
                returnValue = axises[i];
            }
        }
        //Debug.LogError(returnValue);
        return returnValue;
    }
    /// <summary>
    /// 判断轴
    /// </summary>
    /// <param name="axis"></param>
    /// <param name="vector"></param>
    /// <returns></returns>
    public static bool AxisJudgement(Vector3 axis, Vector3 vector)
    {
        if ((Mathf.Abs(axis.x) > 0.001 && vector.x == 0) || (Mathf.Abs(axis.y) > 0.001 && vector.y == 0) || (Mathf.Abs(axis.z) > 0.001 && vector.z == 0))
        {
            return true;
        }
        return false;
    }
    /// <summary>
    /// 返回最接近的轴方向,优先级是xyz
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public static Vector3 ReturnAxis(Vector3 parameter)
    {
        float minDis = 99999;
        Vector3 returnValue = Vector3.zero;
        //Debug.LogError(axises.Count +""+ axises[0] +"" + axises[1] + "" + axises[2] + "" + axises[3]);
        for (int i = 0; i < Axises.Count; i++)
        {
            if ((parameter - Axises[i]).magnitude < minDis)
            {
                minDis = (parameter - Axises[i]).magnitude;
                returnValue = Axises[i];
            }
        }
        return returnValue;
    }

    /// <summary>
    /// 攻击动画的协程
    /// </summary>
    /// <param name="target">播放动画的主体</param>
    /// <param name="time">动画持续时间的一半</param>
    /// <param name="registe">注销方法</param>
    /// <param name="sentMessage">发送攻击信号方法</param>
    /// <returns></returns>
    public static IEnumerator AttackAnim(GameObject target, Vector3 direction, float time, Action sentMessage)
    {
        RegistAction(1);
        Vector3 start = target.transform.position;
        Vector3 end = start + direction * (float)0.3;
        int lastLong = (int)(time / Time.fixedDeltaTime);
        for (int i = 1; i <= lastLong; i++)
        {
            target.transform.position = Vector3.Lerp(start, end, (float)i / lastLong);
            //Debug.LogError(target.transform.position + "" + PlayerManager.GetInstance().gameObject.transform.position);
            yield return new WaitForFixedUpdate();
        } // 向前
        sentMessage();
        GameObject partical = EffectManager.Instance.spawnParticle(0);
        partical.transform.position = target.transform.position+direction*0.6f;
        AttactkAudio.GetComponent<AudioSource>().Play();
        //TODO 攻击的特效
        for (int i = 1; i <= lastLong; i++)
        {
            target.transform.position = Vector3.Lerp(end, start, (float)i / lastLong);
            //Debug.LogError(target.transform.position + "" + PlayerManager.GetInstance().gameObject.transform.position);
            yield return new WaitForFixedUpdate();
        } // 向后
        RegistAction(-1);
    }
    /// <summary>
    /// 被攻击的反馈 TODO　没做完
    /// </summary>
    /// <param name="target"></param>
    /// <param name="direction">攻击来向：攻击者-被攻击者</param>
    /// <param name="time"></param>
    /// <param name="registe"></param>
    /// <returns></returns>
    public static IEnumerator BeAttacked(GameObject target, Vector3 direction, float time, Action next = null)
    {
        RegistAction(1);
        Vector3 start = target.transform.position;
        Vector3 end = start + direction * (float)-0.1;
        int lastLong = (int)(time / Time.fixedDeltaTime);
        for (int i = 1; i <= lastLong; i++)
        {
            target.transform.position = Vector3.Lerp(start, end, (float)i / lastLong);
            //Debug.LogError(target.transform.position + "" + PlayerManager.GetInstance().gameObject.transform.position);
            yield return new WaitForFixedUpdate();
        } // 向前
        //GameObject partical = EffectManager.Instance.spawnParticle(1);
        //partical.transform.position = target.transform.position+direction;
          //挨打特效
        for (int i = 1; i <= lastLong; i++)
        {
            target.transform.position = Vector3.Lerp(end, start, (float)i / lastLong);
            //Debug.LogError(target.transform.position + "" + PlayerManager.GetInstance().gameObject.transform.position);
            yield return new WaitForFixedUpdate();
        } // 向后

        RegistAction(-1);
        if (next != null)
            next();
    }

    public static void RegistAction(int IsR)
    {
        EventNodeCore.GetInstance().HandleEvent(EventDef.Action * IsR, null, null);
    }

}
